#pragma once

#include <QObject>
#include <memory>
#include "Producer.hpp"
#include "DataProducer.hpp"
#include "Consumer.hpp"
#include "DataConsumer.hpp"
#include "rtc_base/thread.h"
#include "Device.hpp"
#include "Transport.hpp"
#include "websocket/websocket_transport.h"
#include "websocket/i_transport_observer.h"
#include "windows_capture.h"
#include "api/video/video_sink_interface.h"
#include "api/video/video_frame.h"
#include "api/video/i420_buffer.h"

#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "third_party/libyuv/include/libyuv/convert_argb.h"
#include "api/media_stream_interface.h"
#include "api/video/video_frame.h"
#include "E:/mediasoupPro/webrtc-my-demno/webrtcDemoM94/webrtc/include/third_party/libyuv/include/libyuv.h"
#include "media/base/media_channel.h"
#include "media/base/video_common.h"
#include <functional>
class MainWgt;
class VideoRenderer;

class MediasoupEventCB {
public:
	MediasoupEventCB() {};
	virtual void onNewPeer(QString peerId) = 0;
};

namespace vi {

	class VRender :public rtc::VideoSinkInterface<webrtc::VideoFrame> 
	{
	public:
		VRender() {
		
		}
		void OnFrame(const webrtc::VideoFrame& frame) override
		{

			rtc::scoped_refptr<webrtc::I420BufferInterface> buffer(frame.video_frame_buffer()->ToI420());
			if (frame.rotation() != webrtc::kVideoRotation_0) {
				buffer = webrtc::I420Buffer::Rotate(*buffer, frame.rotation());
			}

			memset(m_buffer, 0, 1920 * 1080 * 4);

			libyuv::I420ToARGB(buffer->DataY(), buffer->StrideY(), buffer->DataU(),
				buffer->StrideU(), buffer->DataV(), buffer->StrideV(),
				m_buffer,
				buffer->width() * 4,
				buffer->width(),
				buffer->height());
			if (m_dataFunc){
				m_dataFunc(m_peerId,m_buffer, buffer->width(), buffer->height());
			}
		}
		void setPeerId(QString peerId) {
			m_peerId = peerId;
		}

		void regiestDataFunc(std::function<void(QString, unsigned char*, int, int)> dataFunc){
			m_dataFunc = dataFunc;
		}
	private:
		unsigned char* m_buffer = new unsigned char[1920*1080*4]();
		QString  m_peerId;
		std::function<void(QString, unsigned char*, int, int)>			m_dataFunc = nullptr;
	};

	class MediaCtroller :
		public QObject,
		public mediasoupclient::SendTransport::Listener,
		public mediasoupclient::RecvTransport::Listener,
		public mediasoupclient::Producer::Listener,
		public mediasoupclient::Consumer::Listener,
		public ITransportObserver
	{
		Q_OBJECT
	public:
		MediaCtroller(QObject*parent = nullptr);
		~MediaCtroller();
		void regiestCallback(MediasoupEventCB*cb);
		void regiestFunc(std::function<void(QString ,unsigned char*,int,int)> dataFunc);

		void startMediasoup();
		void connectServer(QString url);
		void enableVideo(bool enable = true);
		void createNewConsumer(std::string msg);
	protected:
		virtual void onOpened();

		virtual void onClosed();

		virtual void onFailed(int errorCode, const std::string& reason);

		virtual void onMessage(const std::string& msg);
		/////////////////

		std::future<void> OnConnect(
			mediasoupclient::Transport* transport, const nlohmann::json& dtlsParameters) override;
		void OnConnectionStateChange(
			mediasoupclient::Transport* transport, const std::string& connectionState) override;
		std::future<std::string> OnProduce(
			mediasoupclient::SendTransport* /*transport*/,
			const std::string& kind,
			nlohmann::json rtpParameters,
			const nlohmann::json& appData) override;

		std::future<std::string> OnProduceData(
			mediasoupclient::SendTransport* transport,
			const nlohmann::json& sctpStreamParameters,
			const std::string& label,
			const std::string& protocol,
			const nlohmann::json& appData) override;
		void OnTransportClose(mediasoupclient::Producer* producer) override;


		// Consumer::Listener
		void OnTransportClose(mediasoupclient::Consumer* consumer) override;
	public Q_SLOTS:
		
	private:
		std::unique_ptr<rtc::Thread>								_networkThread;
		std::unique_ptr<rtc::Thread>								_signalingThread;
		std::unique_ptr<rtc::Thread>								_workerThread;

		std::unique_ptr<std::promise<std::string>>					_promise;

		std::unique_ptr <std::promise<void>>						_promise2 = nullptr;
		vi::WebsocketTransport* _websocket;
		std::shared_ptr<mediasoupclient::Producer>					_camProducer;
		rtc::scoped_refptr<WindowsCapturerTrackSource>				_capturerSource;

		std::unique_ptr<webrtc::TaskQueueFactory>					_taskQueueFactory;
		rtc::scoped_refptr<webrtc::AudioDeviceModule>				_adm;
		std::shared_ptr<mediasoupclient::Device>					_mediasoupDevice;
		std::shared_ptr<mediasoupclient::SendTransport>				_sendTransport;
		std::shared_ptr<mediasoupclient::RecvTransport>				_recvTransport;
		rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>	_peerConnectionFactory;
		std::shared_ptr<mediasoupclient::PeerConnection::Options>	_peerConnectionOptions;

		webrtc::AudioTrackInterface*								m_aTrack = nullptr;

		std::string													m_recvTransportId;

		QList<VRender*>												m_renderList;
		std::function<void(QString, unsigned char*, int, int)>		m_dataFunc = nullptr;
		MediasoupEventCB*											m_mediasoupEventCb = nullptr;
	};
}